package com.duubee.btframe.vo;

import com.duubee.btframe.enums.BtOrder;
import com.duubee.btframe.utils.BtDateUtil;
import com.duubee.btframe.utils.BtFrameUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.duubee.btframe.utils.BtStringUtil;
import com.alibaba.fastjson.JSONObject;

import java.math.BigDecimal;
import java.util.*;

/**
 * vo 条件构造器
 */
@SuppressWarnings(value = "all")
public class BtCondition {

    /**
     * 内置就是一个jsonObject对象(储存数据)
     */
    private JSONObject condition;
    /**
     * 忽略的字段
     */
    private List<String> ignoreField;

    /**
     * 指定查询的字段
     */
    private List<String> field;

    /**
     * 结果去重标识，默认不去重
     */
    private boolean distinct = false;

    /**
     * 查询逻辑删除字段
     */
    private boolean queryLogicDeleted = false;

    //空构造器
    private BtCondition() {
        condition = new JSONObject(16, true);//设置为有序的
    }

    /**
     * 创建空的条件构造器
     *
     * @return BtCondition条件构造器对象
     */
    public static BtCondition create() {
        BtCondition btCondition = new BtCondition();
        return btCondition.eq(null, null);
    }

    /**
     * 通过实体创建条件构造器
     *
     * @param object 对象
     * @return BtCondition条件构造器对象
     */
    public static BtCondition create(Object object) {
        BtCondition btCondition = new BtCondition();
        return btCondition.eq(null, null);
    }

    /**
     * 添加条件(saveOrUpdate使用)
     *
     * @param key 键
     * @return BtCondition条件构造器对象
     */
    public static BtCondition create(String key) {
        return BtCondition.create().eq(key);
    }

    /**
     * 创建条件构造器
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public static BtCondition create(String key, Object value) {
        BtCondition btCondition = new BtCondition();
        return btCondition.eq(key, value);
    }

    /**
     * 转换条件构造器
     *
     * @param reqMap 原条件
     * @return 新的条件
     */
    public static BtCondition create(Map<String, String[]> reqMap) {
        if (reqMap == null) {
            return null;
        }
        BtCondition btCondition = BtCondition.create();

        for (String key : reqMap.keySet()) {
            String[] value = reqMap.get(key);
            if (value.length == 1) {
                switch (key) {
                    case BtFrameUtil.FIELD_COLUMN:
                    case BtFrameUtil.FIELDS_COLUMN:
                        btCondition.assignField(BtStringUtil.disposeArrOrToList(value[0]).toArray(new String[]{}));
                        break;
                    default:
                        if (JSONObject.isValidArray(value[0])) {

                            JSONArray jsonArray = JSONArray.parseArray(value[0]);
                            if (jsonArray.size() > 0) {
                                if (jsonArray.get(0).getClass() == Integer.class || jsonArray.get(0).getClass() == int.class) {
                                    btCondition.eq(key, jsonArray.toJavaList(Integer.class).toArray(new Integer[]{}));
                                } else {
                                    btCondition.eq(key, jsonArray.toJavaList(String.class).toArray(new String[]{}));
                                }
                            }

                        } else if (BtStringUtil.containsRight(key.toUpperCase(), BtFrameUtil.NOTIN)) {
                            btCondition.notIn(BtStringUtil.getLeftStr(key, BtFrameUtil.NOTIN), Arrays.asList(BtStringUtil.disposeArr(value[0])));
                        } else if (BtStringUtil.containsRight(key.toUpperCase(), BtFrameUtil.IN)) {
                            btCondition.in(BtStringUtil.getLeftStr(key, BtFrameUtil.IN), Arrays.asList(BtStringUtil.disposeArr(value[0])));
                        } else {
                            btCondition.eq(key, value[0]);
                        }
                        break;
                }

            } else {
                btCondition.eq(key, value);
            }
        }

        return btCondition;
    }

    /**
     * 删除条件
     *
     * @param key key
     * @return 新的条件
     */
    public BtCondition removeCondition(String key) {
        condition.remove(key);
        return this;
    }

    /**
     * 添加条件(saveOrUpdate使用)
     *
     * @param key 实体类属性
     * @return BtCondition条件构造器对象
     */
    public BtCondition eq(String key) {
        return this.eq(key, null);
    }

    /**
     * 添加条件
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition eq(String key, Object value) {
        if (!BtStringUtil.isEmpty(key)) {
            condition.put(key, value);
        }
        return this;
    }

    /**
     * 添加条件
     *
     * @param table 表类型
     * @param key   实体类属性
     * @param value 值
     * @param <T>   t
     * @return BtCondition条件构造器对象
     */
    public <T> BtCondition eqFk(Class<T> table, String key, Object value) {
        String tableName = table.getSimpleName();
        return this.eq(tableName + "$" + key, value);
    }

    /**
     * 添加条件(不等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition ne(String key, Object value) {
        this.eq(key + BtFrameUtil.NE, value);
        return this;
    }

    /**
     * 添加条件(等于null)
     *
     * @param key 实体类属性
     * @return BtCondition条件构造器对象
     */
    public BtCondition isNull(String key) {
        this.eq(key + BtFrameUtil.ISNULL, "");
        return this;
    }

    /**
     * 添加条件(不等于null)
     *
     * @param key 实体类属性
     * @return BtCondition条件构造器对象
     */
    public BtCondition isNotNull(String key) {
        this.eq(key + BtFrameUtil.ISNOTNULL, "");
        return this;
    }

    /**
     * 添加条件(日期范围查询(开始时间))
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition begin(String key, Object value) {
        this.eq(key + BtFrameUtil.BEGIN, value);
        return this;
    }

    /**
     * 添加条件(日期范围查询(结束时间))
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition end(String key, Object value) {
        this.eq(key + BtFrameUtil.END, value);
        return this;
    }

    /**
     * 添加条件(左模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition leftLike(String key, Object value) {
        this.eq(key + BtFrameUtil.LEFT_LIKE, value);
        return this;
    }

    /**
     * 添加条件(右模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition rightLike(String key, Object value) {
        this.eq(key + BtFrameUtil.RIGHT_LIKE, value);
        return this;
    }

    /**
     * 添加条件(模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition like(String key, Object value) {
        this.eq(key + BtFrameUtil.LIKE, value);
        return this;
    }

    /**
     * 添加条件(not模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition notLike(String key, Object value) {
        this.eq(key + BtFrameUtil.NOTLIKE, value);
        return this;
    }

    /**
     * 添加条件(大于)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition gt(String key, Object value) {
        this.eq(key + BtFrameUtil.GT, value);
        return this;
    }

    /**
     * 添加条件(小于)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition lt(String key, Object value) {
        this.eq(key + BtFrameUtil.LT, value);
        return this;
    }

    /**
     * 添加条件(大于等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition gtEq(String key, Object value) {
        this.eq(key + BtFrameUtil.GT_EQ, value);
        return this;
    }

    /**
     * 结果去重
     *
     * @return 条件构造器
     */
    public BtCondition distinct() {
        this.distinct = true;
        return this;
    }

    /**
     * 添加条件(小于等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @return BtCondition条件构造器对象
     */
    public BtCondition ltEq(String key, Object value) {
        this.eq(key + BtFrameUtil.LT_EQ, value);
        return this;
    }

    /**
     * 添加查询今天数据条件
     *
     * @param key 实体类属性
     * @return BtCondition条件构造器对象
     */
    public BtCondition toDay(String key) {
        this.eq(key + BtFrameUtil.TODAY, "");
        return this;
    }

    /**
     * 添加查询 在某一天的数据
     *
     * @param key  实体类属性
     * @param date 时间 只获取年月日 00:00:00——23:59:59
     * @return BtCondition条件构造器对象
     */
    public BtCondition inDay(String key, Date date) {
        this.begin(key, BtDateUtil.getDayBeginTime(date));
        this.end(key, BtDateUtil.getDayEndTime(date));
        return this;
    }

    /**
     * 添加条件(in)
     *
     * @param key   实体类属性
     * @param param 条件值
     * @return BtCondition条件构造器对象
     */
    public BtCondition in(String key, Object... param) {
        Map<String, Boolean> flag = new HashMap<>();
        if (param != null && param.length > 0) {
            Arrays.stream(param).forEach(res -> {
                if (res != null) {
                    if (res instanceof List) {
                        if (((List) res).size() > 0) {
                            this.eq(key + BtFrameUtil.IN, ((List) res).toArray());
                            flag.put("true", true);
                        }
                    } else {
                        this.eq(key + BtFrameUtil.IN, param);
                        flag.put("true", true);
                    }
                }

            });
        }
        if (flag.size() == 0) {
            this.eq(key + BtFrameUtil.IN, null);
        }

        return this;
    }

    /**
     * 添加条件(not in)
     *
     * @param key   实体类属性
     * @param param 条件值
     * @return BtCondition条件构造器对象
     */
    public BtCondition notIn(String key, Object... param) {
        Map<String, Boolean> flag = new HashMap<>();
        if (param != null && param.length > 0) {
            Arrays.stream(param).forEach(res -> {
                if (res != null) {
                    if (res instanceof List) {
                        if (((List) res).size() > 0) {
                            this.eq(key + BtFrameUtil.NOTIN, ((List) res).toArray());
                            flag.put("true", true);
                        }
                    } else {
                        this.eq(key + BtFrameUtil.NOTIN, param);
                        flag.put("true", true);
                    }
                }
            });
        }
        if (flag.size() == 0) {
            this.eq(key + BtFrameUtil.NOTIN, null);
        }
        return this;
    }

    /**
     * 添加or条件
     *
     * @param btConditions 条件构造器
     * @return BtCondition条件构造器对象
     */
    public BtCondition or(BtCondition... btConditions) {
        if (btConditions != null && btConditions.length > 0) {
            BtCondition[] btConditionsList = this.getBtConditionArr(BtFrameUtil.OR);
            if (btConditionsList == null || btConditionsList.length <= 0) {
                this.eq(BtFrameUtil.OR + IdWorker.getIdStr(), btConditions);
            } else {
                List<BtCondition> btConditions1 = new ArrayList<>();
                for (BtCondition temp : btConditionsList) {
                    btConditions1.add(temp);
                }
                for (BtCondition temp : btConditions) {
                    btConditions1.add(temp);
                }
                this.eq(BtFrameUtil.OR + IdWorker.getIdStr(), btConditions1.toArray());
            }
        }

        return this;
    }

    /**
     * 添加排序
     *
     * @param table   连表
     * @param column  实体类属性
     * @param btOrder 排序方式
     * @param <T>     t
     * @return BtCondition条件构造器对象
     */
    public <T> BtCondition addOrder(Class<T> table, String column, BtOrder btOrder) {

        String tableName = BtFrameUtil.getTableName(table);
        return this.addOrder(tableName + "$" + column, btOrder);

    }

    /**
     * 添加排序
     *
     * @param column  实体类属性
     * @param btOrder 排序方式
     * @return BtCondition条件构造器对象
     */
    public BtCondition addOrder(String column, BtOrder btOrder) {
        if (!BtStringUtil.isEmpty(column)) {
            String columnValue = this.getString(BtFrameUtil.ORDER_COLUMN);
            String orderTypeValue = this.getString(BtFrameUtil.ORDER_TYPE);
            if (BtStringUtil.isEmpty(columnValue) || BtStringUtil.isEmpty(orderTypeValue)) {
                columnValue = "";
                orderTypeValue = "";
            }
            if (columnValue.contains(column)) {
                String[] columns = columnValue.split(",");
                String[] orders = orderTypeValue.split(",");
                StringBuilder columnNewStr = new StringBuilder();
                StringBuilder orderNewStr = new StringBuilder();

                for (int i = 0; i < columns.length; i++) {
                    if (columns[i].equalsIgnoreCase(column)) {
                        columns[i] = column;
                        orders[i] = btOrder.toString();
                    } else {
                        columnNewStr.append(columns[i]);
                        orderNewStr.append(orders[i]);
                    }

                    if (i != columns.length - 1) {

                        columnNewStr.append(",");
                        orderNewStr.append(",");
                    }
                }
                columnValue = columnNewStr.toString();
                orderTypeValue = orderNewStr.toString();

            } else {
                if (BtStringUtil.isEmpty(columnValue) || BtStringUtil.isEmpty(orderTypeValue)) {
                    columnValue = column;
                    orderTypeValue = btOrder.toString();
                } else {
                    columnValue = columnValue + "," + column;
                    orderTypeValue = orderTypeValue + "," + btOrder.toString();
                }

            }


            this.condition.put(BtFrameUtil.ORDER_COLUMN, columnValue);
            this.condition.put(BtFrameUtil.ORDER_TYPE, orderTypeValue);
        }
        return this;
    }

    /**
     * 清除排序
     *
     * @return 条件构造器
     */
    public BtCondition clearOrder() {
        this.condition.remove(BtFrameUtil.ORDER_COLUMN);
        this.condition.remove(BtFrameUtil.ORDER_TYPE);
        return this;
    }

    /**
     * 添加外表分组
     *
     * @param table  表对象
     * @param column 列
     * @param <T>    t
     * @return 条件构造器
     */
    public <T> BtCondition addGroup(Class<T> table, String column) {

        if (BtStringUtil.isNotEmpty(column)) {
            String tableName = BtFrameUtil.getTableName(table);
            if (BtStringUtil.isNotEmpty(tableName)) {
                this.addGroup(tableName + "$" + column);
            }
        }

        return this;
    }


    /**
     * 添加分组
     *
     * @param column 列
     * @return 条件构造器
     */
    public BtCondition addGroup(String column) {

        if (BtStringUtil.isNotEmpty(column)) {
            List<String> columns = this.getStringList(BtFrameUtil.GROUP_BY);


            if (columns == null) {
                columns = new ArrayList<>();
            }

            if (columns.stream().anyMatch(item -> item.equals(column))) {
                columns.remove(column);
            }
            columns.add(column);

            this.condition.put(BtFrameUtil.GROUP_BY, columns);
        }

        return this;
    }

    /**
     * 左连接
     *
     * @param table       连接表实体类
     * @param tColumn     连表列
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <T>         t
     * @return BtCondition条件构造器对象
     */
    public <T> BtCondition leftJoin(Class<T> table, String tColumn, String mColumn, BtCondition btCondition) {
        JSONObject jsonObject = new JSONObject();
        String tableName = BtFrameUtil.getTableName(table);
        jsonObject.put("tableType", table);
        jsonObject.put("tableName", tableName);
        jsonObject.put("tColumn", tColumn);
        jsonObject.put("mColumn", mColumn);
        jsonObject.put("btCondition", btCondition);
        condition.put(BtFrameUtil.LEFT_JOIN + tableName + "_" + tColumn + "_" + mColumn, jsonObject);
        return this;
    }

    /**
     * 右连接
     *
     * @param table       连接表实体类
     * @param tColumn     连表列
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <T>         t
     * @return BtCondition条件构造器对象
     */
    public <T> BtCondition rightJoin(Class<T> table, String tColumn, String mColumn, BtCondition btCondition) {
        JSONObject jsonObject = new JSONObject();
        String tableName = BtFrameUtil.getTableName(table);
        jsonObject.put("tableType", table);
        jsonObject.put("tableName", tableName);
        jsonObject.put("tColumn", tColumn);
        jsonObject.put("mColumn", mColumn);
        jsonObject.put("btCondition", btCondition);
        condition.put(BtFrameUtil.RIGHT_JOIN + tableName + "_" + tColumn + "_" + mColumn, jsonObject);
        return this;
    }

    /**
     * 内连接
     *
     * @param table       连接表实体类
     * @param tColumn     连表列  (一般为id)
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <T>         t
     * @return BtCondition条件构造器对象
     */
    public <T> BtCondition innerJoin(Class<T> table, String tColumn, String mColumn, BtCondition btCondition) {
        JSONObject jsonObject = new JSONObject();
        String tableName = BtFrameUtil.getTableName(table);
        jsonObject.put("tableType", table);
        jsonObject.put("tableName", tableName);
        jsonObject.put("tColumn", tColumn);
        jsonObject.put("mColumn", mColumn);
        jsonObject.put("btCondition", btCondition);
        condition.put(BtFrameUtil.INNER_JOIN + tableName + "_" + tColumn + "_" + mColumn, jsonObject);
        return this;
    }

    /**
     * 忽略字段
     *
     * @param fieldNames 字段名
     * @return 条件构造器
     */
    public BtCondition ignoreField(String... fieldNames) {
        if (this.ignoreField == null) {
            this.ignoreField = new ArrayList<>();
        }
        for (String fieldName : fieldNames) {
            this.ignoreField.add(fieldName);
        }
        return this;
    }

    /**
     * 忽略字段
     *
     * @param fieldName 字段名
     * @return 条件构造器
     */
    public BtCondition clearIgnoreField(String fieldName) {
        if (this.ignoreField != null) {
            this.ignoreField.remove(fieldName);
        }
        return this;
    }

    /**
     * 指定字段
     *
     * @param fieldNames 字段名
     * @return 条件构造器
     */
    public BtCondition assignField(String... fieldNames) {
        if (this.field == null) {
            this.field = new ArrayList<>();
        }
        if (fieldNames != null && fieldNames.length > 0) {
            for (String fieldName : fieldNames) {
                this.field.add(fieldName);
            }
        }

        return this;
    }

    /**
     * 查询逻辑删除
     *
     * @return 条件构造器
     */
    public BtCondition queryLogicDeleted() {
        this.queryLogicDeleted = true;
        return this;
    }

    /**
     * 设置是否查询逻辑删除
     *
     * @param flag 值
     * @return 条件构造器
     */
    public BtCondition setQueryLogicDeleted(boolean flag) {
        this.queryLogicDeleted = flag;
        return this;
    }

    /**
     * 查询逻辑删除
     *
     * @return 结果
     */
    public boolean getQueryLogicDeleted() {
        return this.queryLogicDeleted;
    }

    /**
     * 是否存在忽略字段
     *
     * @return 是否存在
     */
    public boolean existsIgnoreField() {
        return this.ignoreField == null || this.ignoreField.size() < 1;
    }

    /**
     * 是否存在忽略字段
     *
     * @param fieldName 字段名
     * @return 是否存在
     */
    public boolean existsIgnoreField(String fieldName) {
        if (ignoreField == null) {
            return false;
        }
        return this.ignoreField.stream().filter(field -> field.equals(fieldName)).toArray().length > 0;
    }

    /**
     * 是否存在指定字段查询
     *
     * @return 是否存在
     */
    public boolean existsField() {
        return this.field == null || this.field.size() < 1;
    }


    /**
     * 是否存在指定字段
     *
     * @param fieldName 字段名
     * @return 是否存在
     */
    public boolean existsField(String fieldName) {
        if (this.field == null) {
            return false;
        }
        return this.field.stream().filter(field -> field.equals(fieldName)).toArray().length > 0;
    }


    /**
     * 获取key集合
     *
     * @return key集合
     */
    public Set<String> keySet() {
        return this.condition.keySet();
    }

    /**
     * 取Object值
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return this.condition.get(key);
    }

    /**
     * 取String值
     *
     * @param key 键
     * @return 值
     */
    public String getString(String key) {
        return this.condition.getString(key);
    }

    /**
     * 取Integer值
     *
     * @param key 键
     * @return 值
     */
    public Integer getInteger(String key) {
        return this.condition.getInteger(key);
    }

    /**
     * 取Long值
     *
     * @param key 键
     * @return 值
     */
    public Long getLong(String key) {
        return this.condition.getLong(key);
    }

    /**
     * 取Boolean值
     *
     * @param key 键
     * @return 值
     */
    public Boolean getBoolean(String key) {
        return this.condition.getBoolean(key);
    }

    /**
     * 取Date值
     *
     * @param key 键
     * @return 值
     */
    public Date getDate(String key) {
        return this.condition.getDate(key);
    }

    /**
     * 取getSqlDate值
     *
     * @param key 键
     * @return 值
     */
    public java.sql.Date getSqlDate(String key) {
        return this.condition.getSqlDate(key);
    }

    /**
     * 取Short值
     *
     * @param key 键
     * @return 值
     */
    public Short getShort(String key) {
        return this.condition.getShort(key);
    }

    /**
     * 取JSONArray值
     *
     * @param key 键
     * @return 值
     */
    public JSONArray getJSONArray(String key) {
        return this.condition.getJSONArray(key);
    }

    /**
     * 取JSONObject值
     *
     * @param key 键
     * @return 值
     */
    public JSONObject getJSONObject(String key) {
        return this.condition.getJSONObject(key);
    }

    /**
     * 取BigDecimal值
     *
     * @param key 键
     * @return 值
     */
    public BigDecimal getBigDecimal(String key) {
        return this.condition.getBigDecimal(key);
    }

    /**
     * 取String List 值
     *
     * @param key 键
     * @return 值
     */
    public List<String> getStringList(String key) {
        JSONArray jsonArray = this.getJSONArray(key);
        if (jsonArray != null) {
            return jsonArray.toJavaList(String.class);
        }
        return null;
    }

    /**
     * 取Integer List 值
     *
     * @param key 键
     * @return 值
     */
    public List<Integer> getIntegerList(String key) {
        JSONArray jsonArray = this.getJSONArray(key);
        if (jsonArray != null) {
            return jsonArray.toJavaList(Integer.class);
        }
        return null;
    }

    /**
     * 取Date List 值
     *
     * @param key 键
     * @return 值
     */
    public List<Date> getDateList(String key) {
        JSONArray jsonArray = this.getJSONArray(key);
        if (jsonArray != null) {
            return jsonArray.toJavaList(Date.class);
        }
        return null;
    }

    /**
     * 取BigDecimal List 值
     *
     * @param key 键
     * @return 值
     */
    public List<BigDecimal> getBigDecimalList(String key) {
        JSONArray jsonArray = this.getJSONArray(key);
        if (jsonArray != null) {
            return jsonArray.toJavaList(BigDecimal.class);
        }
        return null;
    }


    /**
     * 取BtCondition数组
     *
     * @param key 键
     * @return 条件构造器数组
     */
    public BtCondition[] getBtConditionArr(String key) {
        Object object = this.condition.get(key);
        if (object != null) {
            return (BtCondition[]) object;
        } else {
            return null;
        }
    }

    /**取JSONObject*/
//    public JSONObject getJSONObject(String key){
//        Object object = this.condition.gets(key);
//        if(object != null){
//            return (JSONObject)object;
//        }else {
//            return null;
//        }
//    }

    /**
     * 获取是否去重
     *
     * @return 是否去重
     */
    public boolean getDistinct() {
        return this.distinct;
    }

}
